/* 
 * File:   Stack.cpp
 * Author: chadijir
 * 
 * Created on October 14, 2010, 1:29 PM
 */

#include "Stack.h"
#include "settings.h"

using namespace std;

/**
 * Empty
 */
Stack::Stack() {
}

/**
 * Empty
 */
Stack::Stack(const Stack& orig) {
}

/**
 * Empty
 */
Stack::~Stack() {
}

/**
 * Decorating deque operation
 */
void Stack::push(const State& x) {
    representation.push_back(x);
}
/**
 * Decorating deque operation
 */
void Stack::pop() {
    representation.pop_back();
}
/**
 * Decorating deque operation
 */
State& Stack::top() {
    return representation.back();
}
/**
 * Decorating deque operation
 */
const State& Stack::top() const {
    return representation.back();
}
/**
 * Decorating deque operation
 */
bool Stack::empty() const {
    return representation.empty();
}
/**
 * Decorating deque operation
 */
int Stack::size() const {
    return (int)representation.size();
}
/**
 * Divides stack. Using D-ADZ method. The key is which node is marked as a next
 * node. If a node on the bottom of the stack has as nextNode value larger than
 * nodeCount/2, such state is not considered as a possibility to be sent
 * to another process. Always only maxCount can be sent, default maxCount equals 1.
 */
Stack Stack::divide(unsigned int maxCount) {
    Stack temp;
    while(maxCount-- && representation.size() > 1) {
        State x = representation.front();
        if (x.getNextNode() > x.getSize()/2) {
            return temp;
        }
        temp.push( x );
        representation.pop_front();
    }
    return temp;
}


/**
 * Deserializes stack from char buffer.
 * @param buffer
 * @param bufferSize - size of filled portion of the buffer
 * @param g Graph instance, it is needed to allocate states correctly.
 * @return always should be 0.
 */
int Stack::deserialize(unsigned char* buffer, const int bufferSize, Graph * g) {
    int i, j = 0;
    unsigned char * tempbuffer = new unsigned char[MAX_STATE_SIZE];
    for(i = 0; i < bufferSize; i++) {
        if(buffer[i] == '|') { // end of state
            State st;
            st.init(g);
            st.deserialize(tempbuffer, j);
            j = 0; i++;
            push(st);
        }
        tempbuffer[j++] = buffer[i];
    }

    return 0;

}

/**
 * Format: serialized state, |, serialized state etc. States are pushed from
 * the front, so they can be easily deserialized in correct order. State's
 * serialization method is used to serialize states.
 * @param buffer
 * @param bufferSize if serialized stack cannot fit into buffer, -1, size of
 * filled portion of buffer otherwise
 */
int Stack::serialize(unsigned char* buffer, const int bufferSize) {
    if(MAX_STATE_SIZE*representation.size() > (unsigned int)bufferSize) {return -1;}

    int i = 0;
    int statesize, lastposition = 0;
    unsigned char * tempbuffer = new unsigned char[MAX_STATE_SIZE];
    
    while(!representation.empty()) {
        State st = representation.front(); representation.pop_front();
        statesize = st.serialize(tempbuffer, MAX_STATE_SIZE);
        
        for(i = 0; i < statesize; i++) {
            buffer[lastposition++] = tempbuffer[i];
        }
        buffer[lastposition++] = '|';
    }

    delete [] tempbuffer;
    return lastposition;
}
